package com.activecq.samples.contentfinder.viewhandler;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.search.Predicate;
import com.day.cq.search.eval.FulltextPredicateEvaluator;
import com.day.cq.search.eval.JcrPropertyPredicateEvaluator;
import com.day.cq.wcm.api.NameConstants;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.request.RequestParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* User: david
*/
public class GQLToQueryBuilderConverter {
private static final Logger log = LoggerFactory.getLogger(GQLToQueryBuilderConverter.class);
public static final String DELIMITER = ContentFinderConstants.DELIMITER;
public static final String CF_TYPE = ContentFinderConstants.CF_TYPE;
public static final String CF_PATH = ContentFinderConstants.CF_PATH;
public static final String CF_FULLTEXT = ContentFinderConstants.CF_FULLTEXT;
public static final String CF_MIMETYPE = ContentFinderConstants.CF_MIMETYPE;
public static final String CF_ORDER = ContentFinderConstants.CF_ORDER;
public static final String CF_LIMIT = ContentFinderConstants.CF_LIMIT;
public static final String CF_OFFSET = ContentFinderConstants.CF_OFFSET;
public static final String CF_NAME = ContentFinderConstants.CF_NAME;
public static final String CF_TAGS = ContentFinderConstants.CF_TAGS;
public static final int GROUP_PATH = ContentFinderConstants.GROUP_PATH;
public static final int GROUP_TYPE = ContentFinderConstants.GROUP_TYPE;
public static final int GROUP_NAME = ContentFinderConstants.GROUP_NAME;
public static final int GROUP_MIMETYPE = ContentFinderConstants.GROUP_MIMETYPE;
public static final int GROUP_TAGS = ContentFinderConstants.GROUP_TAGS;
public static final int GROUP_FULLTEXT = ContentFinderConstants.GROUP_FULLTEXT;
public static final int GROUP_PROPERTY_USERDEFINED = ContentFinderConstants.GROUP_PROPERTY_USERDEFINED;
public static final int GROUP_ORDERBY_USERDEFINED = ContentFinderConstants.GROUP_ORDERBY_USERDEFINED;
public static final int GROUP_ORDERBY_SCORE = ContentFinderConstants.GROUP_ORDERBY_SCORE;
public static final int GROUP_ORDERBY_MODIFIED = ContentFinderConstants.GROUP_ORDERBY_MODIFIED;
public static final int DEFAULT_OFFSET = ContentFinderConstants.DEFAULT_OFFSET;
public static final int DEFAULT_LIMIT = ContentFinderConstants.DEFAULT_LIMIT;
/**
* Checks if request forces QueryBuilder mode
*
* @param request
* @return
*/
public static boolean convertToQueryBuilder(final SlingHttpServletRequest request) {
return (has(request, ContentFinderConstants.CONVERT_TO_QUERYBUILDER_KEY) &&
ContentFinderConstants.CONVERT_TO_QUERYBUILDER_VALUE.equals(get(request, ContentFinderConstants.CONVERT_TO_QUERYBUILDER_KEY)));
}
public static Map<String, String> addPath(final SlingHttpServletRequest request, Map<String, String> map) {
if (has(request, CF_PATH)) {
map = put(request, map, CF_PATH, GROUP_PATH, true);
} else {
map.put(CF_PATH, request.getRequestPathInfo().getSuffix());
}
return map;
}
public static Map<String, String> addType(final SlingHttpServletRequest request, Map<String, String> map) {
if (has(request, CF_TYPE)) {
map = put(request, map, CF_TYPE, GROUP_TYPE, true);
}
return map;
}
public static Map<String, String> addName(final SlingHttpServletRequest request, Map<String, String> map) {
if (has(request, CF_NAME)) {
map = put(request, map, CF_NAME, "nodename", GROUP_NAME, true);
}
return map;
}
public static Map<String, String> addOrder(final SlingHttpServletRequest request, Map<String, String> map, final String queryString) {
if (has(request, CF_ORDER)) {
int count = 1;
for (String value : getAll(request, CF_ORDER)) {
value = StringUtils.trim(value);
final String orderGroupId = String.valueOf(GROUP_ORDERBY_USERDEFINED + count) + "_group";
boolean sortAsc = false;
if (StringUtils.startsWith(value, "-")) {
sortAsc = false;
value = StringUtils.removeStart(value, "-");
} else if (StringUtils.startsWith(value, "+")) {
sortAsc = true;
value = StringUtils.removeStart(value, "+");
}
// 20000_orderby : jcr:title
// 20000_orderby.sort : ASC
map.put(orderGroupId, StringUtils.trim(value));
map.put(orderGroupId + ".sort", sortAsc ? Predicate.SORT_ASCENDING : Predicate.SORT_DESCENDING);
count++;
}
} else {
final boolean isPage = isPage(get(request, CF_TYPE));
final boolean isAsset = isAsset(get(request, CF_TYPE));
final String prefix = getPropertyPrefix(request);
if (StringUtils.isNotBlank(queryString)) {
map.put(GROUP_ORDERBY_SCORE + "_orderby", "@" + JcrConstants.JCR_SCORE);
map.put(GROUP_ORDERBY_SCORE + "_orderby.sort", Predicate.SORT_DESCENDING);
}
String modifiedOrderProperty = "@" + JcrConstants.JCR_LASTMODIFIED;
if (isPage) {
modifiedOrderProperty = "@" + prefix + NameConstants.PN_PAGE_LAST_MOD;
} else if (isAsset) {
modifiedOrderProperty = "@" + prefix + JcrConstants.JCR_LASTMODIFIED;
}
map.put(GROUP_ORDERBY_MODIFIED + "_orderby", modifiedOrderProperty);
map.put(GROUP_ORDERBY_MODIFIED + "_orderby.sort", Predicate.SORT_DESCENDING);
}
return map;
}
public static Map<String, String> addMimeType(final SlingHttpServletRequest request, Map<String, String> map) {
final boolean isAsset = isAsset(get(request, CF_TYPE));
final String prefix = getPropertyPrefix(request);
if (isAsset && has(request, CF_MIMETYPE)) {
map.put(GROUP_MIMETYPE + "_group.1_property.operation", "like");
map.put(GROUP_MIMETYPE + "_group.1_property", prefix + DamConstants.DC_FORMAT);
map.put(GROUP_MIMETYPE + "_group.1_property.value", "%" + get(request, CF_MIMETYPE) + "%");
}
return map;
}
public static Map<String, String> addTags(final SlingHttpServletRequest request, Map<String, String> map) {
if (has(request, CF_TAGS)) {
final String prefix = getPropertyPrefix(request);
final String groupId = GROUP_TAGS + "_group";
final String tagProperty = prefix + NameConstants.PN_TAGS;
map.put(groupId + ".p.or", "true");
if (hasMany(request, CF_TAGS)) {
final String[] tags = getAll(request, CF_TAGS);
int i = 1;
for (final String tag : tags) {
map.put(groupId + "." + i + "_property", tagProperty);
map.put(groupId + "." + i + "_tagid", tag);
i++;
}
} else {
map.put(groupId + ".1_property", tagProperty);
map.put(groupId + ".1_tagid", get(request, CF_TAGS));
}
}
return map;
}
public static Map<String, String> addFulltext(final SlingHttpServletRequest request,
Map<String, String> map, final String queryString) {
if (StringUtils.isNotBlank(queryString)) {
final String groupId = GROUP_FULLTEXT + "_group";
map.put(groupId + "." + FulltextPredicateEvaluator.FULLTEXT, queryString);
map.put(groupId + ".p.or", "true");
}
return map;
}
public static Map<String, String> addLimitAndOffset(final SlingHttpServletRequest request, Map<String, String> map) {
if (has(request, CF_OFFSET)) {
final String offset = String.valueOf(getOffset(request));
map.put("p.offset", String.valueOf(offset));
}
if (has(request, CF_LIMIT)) {
final String limit = String.valueOf(getLimit(request));
map.put("p.limit", limit);
} else {
map.put("p.limit", String.valueOf(DEFAULT_LIMIT));
}
return map;
}
public static Map<String, String> addProperty(final SlingHttpServletRequest request, Map<String, String> map, final String requestKey, final int count) {
if (!ArrayUtils.contains(ContentFinderConstants.PROPERTY_BLACKLIST, requestKey)) {
map = putProperty(request, map, requestKey, JcrPropertyPredicateEvaluator.PROPERTY, (GROUP_PROPERTY_USERDEFINED + count), true);
} else {
log.debug("Rejecting property [ {} ] due to blacklist match", requestKey);
}
return map;
}
public static boolean isValidProperty(final String key) {
return (!ArrayUtils.contains(ContentFinderConstants.PROPERTY_BLACKLIST, key));
}
/**
* Checks if the provided key has more than 1 values (comma delimited)
*
* @param request
* @param key
* @return
*/
public static boolean hasMany(SlingHttpServletRequest request, String key) {
final RequestParameter rp = request.getRequestParameter(key);
if (rp == null) {
return false;
}
return getAll(request, key).length > 1;
}
/**
* Checks if the provided key has ANY values (1 or more)
*
* @param request
* @param key
* @return
*/
public static boolean has(SlingHttpServletRequest request, String key) {
if (request.getRequestParameters(key) != null) {
return StringUtils.isNotBlank(request.getRequestParameters(key).toString());
}
return false;
}
/**
* Returns a single value for a query parameter key
*
* @param request
* @param key
* @return
*/
public static String get(SlingHttpServletRequest request, String key) {
return StringUtils.trim(request.getRequestParameter(key).toString());
}
/**
* Returns a String array from a comma delimited list of values
*
* @param request
* @param key
* @return
*/
public static String[] getAll(SlingHttpServletRequest request, String key) {
final RequestParameter rp = request.getRequestParameter(key);
if (rp == null) {
return new String[0];
}
return StringUtils.split(rp.getString(), DELIMITER);
}
/**
* Convenience wrapper
*
* @param request
* @param map
* @param predicate
* @param group
* @param or
* @return
*/
public static Map<String, String> put(SlingHttpServletRequest request, Map<String, String> map, String predicate, int group, boolean or) {
return putAll(map, predicate, getAll(request, predicate), group, or);
}
public static Map<String, String> put(SlingHttpServletRequest request, Map<String, String> map, String requestKey, String predicate, int group, boolean or) {
return putAll(map, predicate, getAll(request, requestKey), group, or);
}
/**
* Used when the request key is different from the Predicate
*
* @param request
* @param map
* @param requestKey
* @param predicate
* @param group
* @param or
* @return
*/
public static Map<String, String> putProperty(SlingHttpServletRequest request, Map<String, String> map, String requestKey, String predicate, int group, boolean or) {
// putAll(map, "property", "jcr:titke", "value", [x,y,z], 10, true)
return putAll(map, predicate, requestKey, JcrPropertyPredicateEvaluator.VALUE, getAll(request, requestKey), group, or);
}
/**
* Helper method for adding comma delimited values into a Query Builder predicate
*
* @param map
* @param predicate
* @param values
* @param group
* @param or
* @return
*/
public static Map<String, String> putAll(Map<String, String> map, String predicate, String[] values, int group, boolean or) {
final String groupId = String.valueOf(group) + "_group";
int count = 1;
for (final String value : values) {
final String predicateId = count + "_" + predicate;
map.put(groupId + "." + predicateId, StringUtils.trim(value));
count++;
}
map.put(groupId + ".p.or", String.valueOf(or));
return map;
}
/**
* @param map
* @param predicateValue => jcr:title
* @param predicate => property
* @param predicateSuffix => value
* @param values => [Square, Triangle]
* @param group => ID
* @param or => true/false
* @return
*/
public static Map<String, String> putAll(Map<String, String> map, String predicate, String predicateValue, String predicateSuffix, String[] values, int group, boolean or) {
final String groupId = String.valueOf(group) + "_group";
map.put(groupId + "." + predicate, predicateValue);
int count = 1;
for (final String value : values) {
final String predicateId = predicate;
final String predicateSuffixId = count + "_" + predicateSuffix;
map.put(groupId + "." + predicateId + "." + predicateSuffixId, StringUtils.trim(value));
count++;
}
map.put(groupId + ".p.or", String.valueOf(or));
return map;
}
/**
* Checks of the query param node type is that of a CQ Page
*
* @param nodeType
* @return
*/
public static boolean isPage(String nodeType) {
return StringUtils.equals(nodeType, "cq:Page");
}
/**
* Checks of the query param node type is that of a DAM Asset
*
* @param nodeType
* @return
*/
public static boolean isAsset(String nodeType) {
return StringUtils.equals(nodeType, "dam:Asset");
}
public static String getPropertyPrefix(final SlingHttpServletRequest request) {
final boolean isPage = isPage(get(request, CF_TYPE));
final boolean isAsset = isAsset(get(request, CF_TYPE));
String prefix = "";
if (isPage) {
prefix = JcrConstants.JCR_CONTENT + "/";
} else if (isAsset) {
prefix = JcrConstants.JCR_CONTENT + "/" + DamConstants.METADATA_FOLDER + "/";
}
return prefix;
}
/**
* Extract the query limit from the ContentFinder Query Parameter notation
*
* @param request
* @return
*/
public static int getLimit(final SlingHttpServletRequest request) {
if (has(request, CF_LIMIT)) {
final String value = get(request, CF_LIMIT);
final String[] limits = StringUtils.split(value, "..");
if (value.matches("(\\d)+\\.\\.(\\d)+")) {
// 10..20
return Integer.parseInt(limits[1]) - Integer.parseInt(limits[0]);
} else if (value.matches("(\\d)+\\.\\.(\\d)+")) {
// ..20
return Integer.parseInt(limits[0]);
} else if (value.matches("(\\d)+\\.\\.(\\d)+")) {
// 20..
return -1;
}
}
return DEFAULT_LIMIT;
}
/**
* Extract the query offset from the ContentFinder Query Parameter notation
*
* @param request
* @return
*/
public static int getOffset(final SlingHttpServletRequest request) {
if (has(request, CF_LIMIT)) {
final String value = get(request, CF_LIMIT);
final String[] limits = StringUtils.split(value, "..");
if (value.matches("(\\d)+\\.\\.(\\d)+")) {
// 10..20
return Integer.parseInt(limits[0]);
} else if (value.matches("(\\d)+\\.\\.(\\d)+")) {
// ..20
return Integer.parseInt(limits[0]);
} else if (value.matches("(\\d)+\\.\\.(\\d)+")) {
// 20..
return Integer.parseInt(limits[0]);
}
}
return DEFAULT_OFFSET;
}
}